#include <iostream>
#include <ctime>
#include <vector>
#include <string>
#include <algorithm>

struct PCB {
    std::string pid_name;
    char state;
    int priority;
    int neededTime;
    int arrivalTime;
    int totalWaitTime;

    PCB(const std::string& pname, char pstate, 
        int ppriority, int pneedTime, int parrival, int ptotaltime = 0)
        : pid_name(pname),
          state(pstate),
          priority(ppriority),
          neededTime(pneedTime),
          arrivalTime(parrival),
          totalWaitTime(ptotaltime)
    {}
    
};

const static int pcb_num = 10;

bool cmp(PCB* x, PCB* y) {
    return x->neededTime < y->neededTime;
}

void SJF_func(std::vector<PCB*>& pcbs) {
    // Sort by neededTime and then by arrivalTime
    std::sort(pcbs.begin(), pcbs.end(), cmp);
    int currentTime = 0;
    int totaltime = 0;
    for (auto& pcb : pcbs) {
        if (currentTime < pcb->arrivalTime) {
            currentTime = pcb->arrivalTime;
        }
        
        int waitTime = currentTime - pcb->arrivalTime;
        std::cout << pcb->pid_name << " finished, waiting time is: " << waitTime << std::endl;
        pcb->totalWaitTime = waitTime;
        currentTime += pcb->neededTime;
        totaltime += waitTime;
        pcb->state = 'r'; // Mark the process as running
    }
    std::cout << "All processes are completed!" << std::endl;
    float ave_time = static_cast<float>(totaltime) / pcb_num;
    std::cout << "Average waiting time is " << ave_time << std::endl;
}

int main() {
    srand(time(0));
    std::vector<PCB*> pcbs;

    for (int i = 0; i < pcb_num; i++) {
        const std::string name = "Process-" + std::to_string(i);
        int arrivalTime = 1 + rand() % 20;
        int needTime = 10 + rand() % 41;
        PCB* pcb = new PCB(name, 'w', 80, needTime, arrivalTime);
        pcbs.push_back(pcb);
        std::cout << "Generator: " << name 
            << " is generated, neededTime = " << needTime 
            << ", arrvalTime = " << arrivalTime << std::endl;
    }

    SJF_func(pcbs);

    for (auto& p : pcbs)
        delete p;
    return 0;
}